package com.vcredit.creditcat.service.product.h5;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.fasterxml.jackson.core.type.TypeReference;
import com.vcredit.creditcat.dto.product.h5.RepaymentBillPageData;
import com.vcredit.creditcat.dto.product.h5.RepaymentBillPageDataItem;
import com.vcredit.creditcat.dto.product.h5.RepaymentDto;
import com.vcredit.creditcat.dto.product.h5.RepaymentplainDto;
import com.vcredit.creditcat.dto.product.h5.RepaymentplainItemDto;
import com.vcredit.creditcat.enumtype.LoanBillStatusEnum;
import com.vcredit.creditcat.enumtype.ProductApiEnum;
import com.vcredit.creditcat.enumtype.ProductAuditResultEnum;
import com.vcredit.creditcat.enumtype.product.h5.LoanOrderStatusEnum;
import com.vcredit.creditcat.model.Cust;
import com.vcredit.creditcat.model.CustProductApply;
import com.vcredit.creditcat.model.MerchantProduct;
import com.vcredit.creditcat.model.ProcessSpecial;
import com.vcredit.creditcat.model.RepaymentplainItem;
import com.vcredit.creditcat.model.RepaymentplainSummary;
import com.vcredit.creditcat.service.CustProductApplyService;
import com.vcredit.creditcat.service.MerchantProductService;
import com.vcredit.creditcat.service.ProductApiUrlService;
import com.vcredit.creditcat.service.RepaymentplainItemService;
import com.vcredit.creditcat.service.RepaymentplainSummaryService;
import com.vcredit.creditcat.service.product.CommonProductApplyNewService;
import com.vcredit.creditcat.service.speedloan.ProcessSpecialService;
import com.vcredit.creditcat.util.BeanUtil;
import com.vcredit.creditcat.util.ConcurrentDateUtil;
import com.vcredit.creditcat.util.Utility;
import com.vcredit.creditcat.vo.product.h5.CommonResultVo;
import com.vcredit.creditcat.vo.product.h5.RepaymentPlainBizData;
import com.vcredit.creditcat.vo.product.h5.RepaymentPlainItem;
import com.vcredit.framework.annotation.Log;
import com.vcredit.framework.exception.BaseException;
import com.vcredit.framework.util.JacksonUtil;

@Service
public class RepaymentService {
	
	private static final Logger LOG = LoggerFactory.getLogger(RepaymentService.class);
	
	@Autowired
	private ProductApiUrlService productApiUrlService;
	@Autowired
	private CustProductApplyService custProductApplyService;
	@Autowired
	private CommonApiRequestService commonApiRequestService;
	@Autowired
	private CommonProductApplyNewService commonProductApplyNewService;
	@Autowired
	private RepaymentplainSummaryService repaymentplainSummaryService;
	@Autowired
	private RepaymentplainItemService repaymentplainItemService;
	@Autowired
	private MerchantProductService merchantProductService;
	@Autowired
	private ProcessSpecialService processSpecialService;

	@Log
	public RepaymentDto repayment(Cust cust, Long productId, RepaymentDto param) throws Exception {
		CustProductApply custProductApply = custProductApplyService.findByCustAndProduct(cust.getCustId(), productId);
		if(null == custProductApply || StringUtils.isEmpty(custProductApply.getOrderId())) {
			throw new BaseException("参数不正确");
		}
		
		Map<String,String> paramMap = new HashMap<String,String>();
		paramMap.put("user_id", AfterCreditService.CUSTID_PREFIX + cust.getCustId());
		paramMap.put("order_id", custProductApply.getOrderId());
		if(StringUtils.isNotBlank(param.getVercode())) {
			paramMap.put("vercode", param.getVercode());
		}
		
		String paramJson = JacksonUtil.Obj2Json(paramMap);
		LOG.info("------------RepaymentService.repayment入参：" + paramJson);
		String resultJson = commonApiRequestService.wrapRequest(commonProductApplyNewService.getProductApiUrl(productId, ProductApiEnum.REPAYMENT.getType()), paramJson, false);
		LOG.info("------------RepaymentService.repayment出参：" + resultJson);
		CommonResultVo<Object> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<Object>>(){});
		
		if(commonResult.isSuccess()) { // 成功
			return new RepaymentDto(false, null, 1, null);
		} else if(commonResult.getCode() == 2) { // 需要验证码
			return new RepaymentDto(true, null, 0, commonResult.getMsg());
		} else {
			throw new BaseException(commonResult.getMsg());
		}
	}

	@Log
	@Transactional
	public void insertOrUpdateRepaymentplan(Long productId,RepaymentplainDto repaymentplainDto) throws BaseException {
		if(null == repaymentplainDto.getOrderId() || null == productId) {
			throw new BaseException("参数不正确");
		}
		CustProductApply condition = new CustProductApply();
		condition.setProductId(productId);
		condition.setOrderId(repaymentplainDto.getOrderId());
		List<CustProductApply> custProductApplys = custProductApplyService.findByConditions(condition);
		if(Utility.isNullOrEmpty(custProductApplys)) {
			throw new BaseException("参数不正确");
		}
		
		CustProductApply custProductApply = custProductApplys.get(0);
		Long custId = custProductApply.getCustId();
		
		List<RepaymentplainItem> repaymentplainItems = BeanUtil.copy(repaymentplainDto.getList(), RepaymentplainItem.class);
		// 根据回调的数据更新审批状态值
		this.updateProductApplyAuditResult(custProductApply,repaymentplainDto,repaymentplainItems);
		
		RepaymentplainSummary param = new RepaymentplainSummary();
		param.setProductId(productId);
		param.setOrderId(repaymentplainDto.getOrderId());
		param.setCustId(custId);
		List<RepaymentplainSummary> repaymentplainSummarys = repaymentplainSummaryService.find(param);
		if(Utility.isNullOrEmpty(repaymentplainSummarys)) { 
			// 新增还款计划总览
			RepaymentplainSummary repaymentplainSummary = new RepaymentplainSummary();
			BeanUtil.copy(repaymentplainDto, repaymentplainSummary);
			repaymentplainSummary.setProductId(productId);
			repaymentplainSummary.setCustId(custId);
			repaymentplainSummaryService.insert(repaymentplainSummary);
			
			// 新增还款计划项
			if(Utility.isNullOrEmpty(repaymentplainDto.getList())) {
				return;
			}
			for (RepaymentplainItem repaymentplainItem : repaymentplainItems) {
				repaymentplainItem.setRepaymentplainSummaryId(repaymentplainSummary.getId());
			}
			repaymentplainItemService.batchInsert(repaymentplainItems);
		} 
		
		else { 
			// 更新还款计划总览
			RepaymentplainSummary repaymentplainSummary = repaymentplainSummarys.get(0);
			RepaymentplainSummary copy = new RepaymentplainSummary();
			BeanUtil.copy(repaymentplainDto, copy);
			copy.setId(repaymentplainSummary.getId());
			repaymentplainSummaryService.update(copy);
			
			// 查询所有对应的还款计划项
			RepaymentplainItem repaymentplainItemParam = new RepaymentplainItem();
			repaymentplainItemParam.setRepaymentplainSummaryId(repaymentplainSummary.getId());
			List<RepaymentplainItem> findList = repaymentplainItemService.find(repaymentplainItemParam);
			if(Utility.isNullOrEmpty(findList)) {
				// 没有就插入
				for (RepaymentplainItem repaymentplainItem : repaymentplainItems) {
					repaymentplainItem.setRepaymentplainSummaryId(repaymentplainSummary.getId());
				}
				repaymentplainItemService.batchInsert(repaymentplainItems);
				return;
			}
			
			for (RepaymentplainItem repaymentplainItem : repaymentplainItems) {// 接口调用的数据
				repaymentplainItem.setRepaymentplainSummaryId(repaymentplainSummary.getId());
				boolean flag = true; // 控制循环标志位
				for (RepaymentplainItem find : findList) { // 数据库保存的数据
					if(repaymentplainItem.getPeriodNo().intValue() == find.getPeriodNo().intValue()) {
						// 如果数据库中有这个期数的数据，就更新为回调回来的数据
						repaymentplainItem.setId(find.getId());
						repaymentplainItemService.update(repaymentplainItem);
						flag = false;
						break;
					}
				}
				if(flag) {
					// 如果数据库中没有这个期数的数据，就插入回调回来的数据
					repaymentplainItemService.insert(repaymentplainItem);
				}
			}
		}
	}

	private void updateProductApplyAuditResult(
			CustProductApply custProductApply,
			RepaymentplainDto repaymentplainDto,
			List<RepaymentplainItem> repaymentplainItems) {
		
		// 已结清
		if(repaymentplainDto.getTotalPeriod().intValue() == repaymentplainDto.getFinishPeriod().intValue()) {
			custProductApply.setAuditResult(LoanOrderStatusEnum.End.getAuditResult());
			custProductApplyService.update(custProductApply);
			return;
		}
		
		for(RepaymentplainItem repaymentplainItem : repaymentplainItems) {
			String billStatus = repaymentplainItem.getBillStatus();
			if(LoanBillStatusEnum.Expired.getStatus().equals(billStatus)) {
				// 已逾期
				custProductApply.setAuditResult(LoanOrderStatusEnum.Expired.getAuditResult());
				custProductApplyService.update(custProductApply);
				return;
			}
		}
		
		// 其他状态都为还款中
		custProductApply.setAuditResult(LoanOrderStatusEnum.Reoayment.getAuditResult());
		custProductApplyService.update(custProductApply);
	}

	/**
	 * 查询还款计划
	 * @author zhaoqi01
	 * @param cust
	 * @throws Exception 
	 */
	@Log
	@Transactional
	public RepaymentBillPageData queryRepaymentplan(Cust cust) throws Exception {
		RepaymentBillPageData result = new RepaymentBillPageData();
		
		List<Integer> auditResults = new ArrayList<Integer>();
		auditResults.add(ProductAuditResultEnum.Reoayment.getCode()); // 还款中
		auditResults.add(ProductAuditResultEnum.Expired.getCode()); // 逾期中
		auditResults.add(ProductAuditResultEnum.End.getCode()); // 完结
		List<CustProductApply> custProductApplys = custProductApplyService.findByCustAndAuditResults(cust.getCustId(),auditResults);
		if(Utility.isNullOrEmpty(custProductApplys)) {
			return result;
		}
		
		List<ProcessSpecial> allProcessSpecial = processSpecialService.findAll();
		for (CustProductApply custProductApply : custProductApplys) {
			Long productId = custProductApply.getProductId();
			String productApiUrl = commonProductApplyNewService.getProductApiUrl(productId, ProductApiEnum.QUERY_REPAYMENTPLAIN.getType());
			if(null == productApiUrl) { // 没有配置还款计划的API接口地址，说明该产品还没有对接还款
				continue;
			}
			
			Map<String,String> paramMap = new HashMap<String,String>();
			paramMap.put("user_id", AfterCreditService.CUSTID_PREFIX + cust.getCustId());
			paramMap.put("order_id", custProductApply.getOrderId());
			
			String paramJson = JacksonUtil.Obj2Json(paramMap);
			LOG.info("------------RepaymentService.queryRepaymentplan入参：" + paramJson);
			String resultJson = commonApiRequestService.wrapRequest(productApiUrl, paramJson, false);
			LOG.info("------------RepaymentService.queryRepaymentplan出参：" + resultJson);
			CommonResultVo<RepaymentPlainBizData> commonResult = JacksonUtil.Json2Obj(resultJson, new TypeReference<CommonResultVo<RepaymentPlainBizData>>(){});
		
			if(!commonResult.isSuccess()) {
				throw new BaseException(commonResult.getMsg());
			}
			
			RepaymentplainDto data = this.packageRepaymentplainDto(commonResult.getData());
			// 封装页面数据
			Map<Long, MerchantProduct> allMerchantProduct = merchantProductService.findAll();
			RepaymentBillPageDataItem item = this.packagePageDataItem(data,productId,
					allMerchantProduct.get(productId.longValue()),
					this.getProcessSpecialByProductId(productId,allProcessSpecial),
					custProductApply.getOrderId());
			result.getList().add(item);
			
			// 保存数据库
			this.insertOrUpdateRepaymentplan(productId, data);
		}
	
		return result;
	}
	
	private ProcessSpecial getProcessSpecialByProductId(Long productId,
			List<ProcessSpecial> allProcessSpecial) {
		for (ProcessSpecial processSpecial : allProcessSpecial) {
			if(processSpecial.getProductId().longValue() == productId) {
				return processSpecial;
			}
		}
		return null;
	}

	private RepaymentplainDto packageRepaymentplainDto(RepaymentPlainBizData bizData) {
		RepaymentplainDto repaymentplainDto = new RepaymentplainDto();
		repaymentplainDto.setOrderId(bizData.getOrder_id());
		repaymentplainDto.setTotalAmount(bizData.getTotal_amount());
		repaymentplainDto.setCharge(bizData.getCharge());
		repaymentplainDto.setAlpaid(bizData.getAlpaid());
		repaymentplainDto.setBepaid(bizData.getBepaid());
		repaymentplainDto.setTotalPeriod(bizData.getTotal_period());
		repaymentplainDto.setFinishPeriod(bizData.getFinish_period());
		
		List<RepaymentplainItemDto> list = new ArrayList<RepaymentplainItemDto>();
		for(RepaymentPlainItem item : bizData.getList()) {
			RepaymentplainItemDto dto = new RepaymentplainItemDto();
			dto.setPeriodNo(item.getPeriod_no());
			dto.setDueTime(item.getDue_time());
			dto.setAmount(item.getAmount());
			dto.setOverdueFee(item.getOverdue_fee());
			dto.setBillStatus(item.getBill_status());
			dto.setPayType(item.getPay_type());
			dto.setPrinciple(item.getPrinciple());
			dto.setInterest(item.getInterest());
			dto.setSuccessTime(item.getSuccess_time());
			
			list.add(dto);
		}
		
		repaymentplainDto.setList(list);
		return repaymentplainDto;
	}

	private RepaymentBillPageDataItem packagePageDataItem(
			RepaymentplainDto data, Long productId, 
			MerchantProduct merchantProduct, ProcessSpecial processSpecial,
			String orderId) throws ParseException, UnsupportedEncodingException {
		
		RepaymentBillPageDataItem result = new RepaymentBillPageDataItem();
		result.setProductId(productId);
		result.setProductName(merchantProduct.getProductName());
		result.setProductIcon(merchantProduct.getProductIcon());
		// 兼容有的产品需要跳转到对方H5进行还款
		if(StringUtils.isNotBlank(processSpecial.getRepaymentJump())) {
			result.setNeedJump(true);
			StringBuilder sb = new StringBuilder();
			String[] jumpArr = processSpecial.getRepaymentJump().split(",");
			sb.append(jumpArr[0].trim());
			sb.append("?");
			sb.append("order_sn=").append(orderId);
			sb.append("&");
			sb.append("return_url=").append(URLEncoder.encode(jumpArr[1].trim(),"UTF-8"));
			result.setRepaymentJumpUrl(sb.toString());
		} else {
			result.setNeedJump(false);
		}
		
		String lastRepaymentDate = null; // 最后还款时间
		Integer currentPeriod = 0; // 当前还款期数
		Boolean needRepayment = data.getBepaid().compareTo(BigDecimal.ZERO) == 1 ? true : false; 
		
		result.setBepaid(data.getBepaid()); // 待还金额
		result.setTotalPeriod(data.getTotalPeriod()); // 总期数
		result.setNeedRepayment(needRepayment);// 是否需要还款
		
		List<RepaymentplainItemDto> list = data.getList();
		if(Utility.isNullOrEmpty(list)) {
			result.setLastRepaymentDate(lastRepaymentDate);
			result.setCurrentPeriod(currentPeriod);
			return result;
		}
		
		for (RepaymentplainItemDto repaymentplainItemDto : list) {
			if(repaymentplainItemDto.getPeriodNo() > currentPeriod) {
				currentPeriod = repaymentplainItemDto.getPeriodNo();
				lastRepaymentDate = repaymentplainItemDto.getDueTime(); // 最后还款时间
			}
		}
		
		if(null != lastRepaymentDate) {
			lastRepaymentDate = new SimpleDateFormat("MM月dd日")
				.format(ConcurrentDateUtil.getDate(lastRepaymentDate));
		}
		
		result.setCurrentPeriod(currentPeriod);
		result.setLastRepaymentDate(lastRepaymentDate);
		
		return result;
	}
}
